package com.gzz.orchid.common.webmvc.support;

import com.gzz.orchid.common.core.exception.ArgumentException;
import com.gzz.orchid.common.core.util.I18nUtil;
import io.undertow.server.handlers.form.MultiPartParserDefinition;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.UnexpectedTypeException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.TypeMismatchDataAccessException;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;

/**
 * 全局异常处理
 *
 * @author higmd
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 自定义验证异常
     * Bean 校验异常 Validate
     * 校验异常处理方法
     * 处理 MethodArgumentNotValidException 异常的方法。
     * * 当控制器中的方法参数验证失败时，会抛出此异常，此方法会对其进行处理。
     *
     * @param ex 捕获到的 MethodArgumentNotValidException 异常实例
     * @return 返回一个 ProblemDetail 对象，包含验证失败的详细信息，用于返回给客户端
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class) //400
    public HttpResult exceptionHandler(MethodArgumentNotValidException ex) {
        log.error("数据处理异常MethodArgumentNotValidException: " + ex.getMessage());
        //
        List<Map<String, String>> errorList = ex.getBindingResult()
                .getFieldErrors()
                .stream()
                .map(fieldError -> Map.of(
                        "field", fieldError.getField()
                        , "message", fieldError.getDefaultMessage()
                ))
                .collect(Collectors.toList());

        return HttpResult.failure()
                .message(ex.getMessage())
                .data(errorList);
    }

    /**
     * 方法参数校验异常 Validate
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public HttpResult exceptionHandler(ConstraintViolationException ex) {
        log.error("方法参数校验异常信息 ConstraintViolationException: {}", ex.getMessage());
        List<Map<String, String>> errorList = ex.getConstraintViolations()
                .stream()
                .map(violation -> Map.of(
                        "field", violation.getPropertyPath().toString()
                        , "message", I18nUtil.message(violation.getMessage())
                ))
                .collect(Collectors.toList());
        return HttpResult.failure()
                .message(ex.getMessage())
                .data(errorList);
    }

    /**
     * 统一处理文件过大问题.
     */

    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public HttpResult exceptionHandler(MaxUploadSizeExceededException ex) {
        log.error("上传文件过大 ex={}", ex.getMessage());
        return HttpResult.failure()
                .message(ex.getMessage());
    }

    /**
     * 处理文件上传大小超限制
     */
    @ExceptionHandler(value = MultipartException.class)
    public HttpResult fileUploadExceptionHandler(MultipartException ex) {
        Throwable throwable = ex.getRootCause();
        //        if (throwable instanceof FileSizeLimitExceededException) {
        //            log.error("上传文件过大", exception);
        //            return HttpResult.failure();
        //        }
        // 容器undertow文件上传过大异常支持
        if (throwable instanceof MultiPartParserDefinition.FileTooLargeException) {
            log.error("总上传文件过大", ex);
            return HttpResult.failure()
                    .message("总上传文件过大");
        }
        log.error("上传文件异常", ex);
        return HttpResult.failure()
                .message("上传文件过大");
    }

    /*
      自定义业务异常类型
     */
    //    @ExceptionHandler(value = BizzException.class)
    //    public HttpResult exceptionHandler(BizzException ex) {
    //        log.error("数据处理异常BusinessException: {}", ex.getMessage());
    //        return HttpResult.failure(ex.getMessage());
    //    }

    /**
     * 自定义参数异常类型
     */
    @ExceptionHandler(value = ArgumentException.class)
    public HttpResult exceptionHandler(ArgumentException ex) {
        log.error("数据处理异常ArgumentException: {}", ex.getMessage());
        return HttpResult.failure()
                .message(ex.getMessage());
    }

    /**
     * 验证数据
     */
    @ExceptionHandler(UnexpectedTypeException.class)
    public HttpResult exceptionHandler(UnexpectedTypeException ex) {
        log.error("验证数据类型，{}", ex.getMessage());
        return HttpResult.failure()
                .message(ex.getMessage());
    }


    /**
     * 404 找不到
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    public HttpResult handleNoHandlerFoundException(NoHandlerFoundException e) {
        String errorCode = "404";
        String errorMsg = "找不到对应处理方法资源";
        log.error("找不到系统资源{}, {}", errorCode, e.getRequestURL());
        //return new ResponseEntity<>(new ErrorResponse(errorCode, errorMsg), HttpStatus.NOT_FOUND);
        return HttpResult.failure()
                .message(errorMsg);
    }


    /**
     * 请求参数不全异常
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public HttpResult exceptionHandler(MissingServletRequestParameterException ex) {
        log.error("数据处理异常MissingServletRequestParameterException: " + ex.getMessage());
        //"下的请求参数不全："+pe.getMessage());
        return HttpResult.failure()
                .message("访问请求参数不全");
    }


    //    @ExceptionHandler(UndeclaredThrowableException.class)
    //    public HttpResult exceptionHandler(UndeclaredThrowableException  e) {
    //        Throwable throwable = e.getUndeclaredThrowable();
    //        String errorCode = "";
    //        String errorMsg = "";
    //        if (throwable != null && throwable instanceof DLException) {
    //            errorCode = ((DLException) throwable).getCode();
    //            errorMsg = ((DLException) throwable).getMsg();
    //        } else {
    //            errorCode = "SYSERROR";
    //            errorMsg = "系统繁忙,请稍后再试";
    //            log.error(" Exception: " + e.getClass().toString() + "\n" + getExceptionAllinformation(e));
    //        }
    //        log.error("数据处理异常UndeclaredThrowableException: " + ex.getMessage());
    //        return HttpResult.failure("请求方式不正确");
    //    }

    /**
     * 消息转换失败
     */
    @ExceptionHandler(HttpMessageConversionException.class)
    public HttpResult exceptionHandler(HttpMessageConversionException ex) {
        log.error("数据处理异常HttpMessageConversionException: " + ex.getMessage());
        return HttpResult.failure().message(ex.getMessage());
    }

    /**
     * 缺少请求体异常处理器
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public HttpResult exceptionHandler(HttpMessageNotReadableException ex) {
        log.error("数据处理异常HttpMessageNotReadableException: " + ex.getMessage());
        return HttpResult.failure()
                .message(ex.getMessage());
    }

    /**
     * 请求方式异常
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public HttpResult exceptionHandler(HttpRequestMethodNotSupportedException ex) {
        log.error("数据处理异常HttpRequestMethodNotSupportedException: " + ex.getMessage());
        return HttpResult.failure()
                .message(ex.getMessage());
    }

    /**
     * 绑定数据类型异常
     */
    @ExceptionHandler(value = BindException.class)
    public HttpResult exceptionHandler(BindException ex) {
        log.error("数据处理异常BindException: " + ex.getMessage());
        List<String> errList = null;
        List<ObjectError> allErrors = ex.getBindingResult().getAllErrors();
        errList = allErrors.stream().filter(Objects::nonNull).map(err -> {
            FieldError v = (FieldError) err;
            return "typeMismatch".equalsIgnoreCase(v.getCode()) ? "数据类型不匹配" : v.getDefaultMessage();
        }).collect(Collectors.toList());

        return HttpResult.failure()
                .message(ex.getMessage())
                .data(errList);
    }

    /**
     * 处理空指针的异常
     */
    @ExceptionHandler(value = NullPointerException.class)
    public HttpResult exceptionHandler(NullPointerException ex) {
        log.error("数据处理异常NullPointerException: 发生空指针异常！原因是:{}", ex.getMessage());
        return HttpResult.failure()
                .message(ex.getMessage());
    }

    /**
     * Java类型和数据类型不匹配
     */
    @ExceptionHandler(value = TypeMismatchDataAccessException.class)
    public HttpResult exceptionHandler(TypeMismatchDataAccessException ex) {

        log.error("Java类型和数据类型不匹配TypeMismatchDataAccessException,　{}", ex.getMessage());
        return HttpResult.failure()
                .message(ex.getMessage());
    }

    /**
     * 非法参数IllegalArgumentException
     */
    @ExceptionHandler(value = IllegalArgumentException.class)
    public HttpResult exceptionHandler(IllegalArgumentException ex) {
        log.error("非法参数IllegalArgumentException,　{}", ex.getMessage());
        return HttpResult.failure()
                .message(ex.getMessage());
    }

    /**
     * 非法状态
     */
    @ExceptionHandler(value = IllegalStateException.class)
    public HttpResult exceptionHandler(IllegalStateException ex) {
        log.error("IllegalStateException,　{}", ex.getMessage());
        return HttpResult.failure()
                .message(ex.getMessage());
    }

    /**
     * 操作超时
     */
    @ExceptionHandler(value = TimeoutException.class)
    public HttpResult exceptionHandler(TimeoutException ex) {
        log.error("TimeoutException,　{}", ex.getMessage());
        return HttpResult.failure()
                .message(ex.getMessage());
    }

    /********************************************************************************************************/
    /**
     * 运行时异常
     */
    @ExceptionHandler(value = RuntimeException.class)
    public HttpResult exceptionHandler(RuntimeException e) {
        log.error("运行时异常: " + e.getMessage());
        return HttpResult.failure()
                .message(e.getMessage());
    }

    /**
     * 全局异常捕捉处理
     */
    @ExceptionHandler(value = Exception.class)
    public HttpResult exceptionHandler(Exception ex) {
        log.error("Global数据处理异常Exception: 异常类名 {}, 信息内容 {}", ex.getClass().getCanonicalName(), ex.getMessage());
        if (ex instanceof ArithmeticException) {
            log.error("数据处理异常Exception:  运算出错 {}", ex.getMessage());
        } else if (ex instanceof NoHandlerFoundException) {
            log.error("NoHandlerFoundException 请检查请求路径或者类型是否正确 {}", ex.getMessage());
        } else {
            log.error("Other Exception 其他异常。。" + ex.getClass().getCanonicalName());
        }
        return HttpResult.failure()
                .message(ex.getMessage() == null ? "系统异常" : ex.getMessage());
    }

    /**
     * 合并异常信息
     */
    public String combinerErrors(List<ObjectError> errors) {
        StringBuilder sb = new StringBuilder();
        errors.forEach(
                error -> sb.append(error.getDefaultMessage()).append(";")
        );
        return sb.toString();
    }
}
